package com.yuven.appframework.util;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;

import androidx.core.content.FileProvider;

import com.yuven.appframework.config.AppFrameWorkConstant;
import com.yuven.baselib.utils.Logger;
import com.hjq.toast.ToastUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class FileUtil {

    public static String LOG_DIR = "";
    public static String CACHE_DIR = "";

    private static final String PNG_FILE_PREFIX = "IMG_";
    private static final String PNG_FILE_SUFFIX = ".png";

    public static void initDir(Context context) {
        //miniSDK > 23
        LOG_DIR = context.getExternalFilesDir("log").getPath() + File.separator;
        Logger.i("LOG_DIR:" + LOG_DIR);
        File dirLog = new File(LOG_DIR);
        if (!dirLog.exists()) {
            dirLog.mkdirs();
        }
        CACHE_DIR = context.getExternalCacheDir().getPath() + File.separator;
        Logger.i("CACHE_DIR:" + CACHE_DIR);
        File dirCache = new File(CACHE_DIR);
        if (!dirCache.exists()) {
            dirCache.mkdirs();
        }
    }

    /**
     * 保存单张bitmap到Pictures/AppFrameWorkConstant.PIC_SAVE_DIR_NAME目录(不压缩)
     */
    public static void saveBitmapToPictures(Context context, Bitmap bmp, String toastMsg) {
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            uri = saveBitmapAboveQ(context, bmp);
        } else {
            uri = saveBitmapLegacy(context, bmp);
        }
        if (uri != null) {
            if (!TextUtils.isEmpty(toastMsg)) {
                ToastUtils.show(toastMsg);
            }
        } else {
            ToastUtils.show("图片保存失败");
        }
    }

    /**
     * 保存bitmap到Pictures/AppFrameWorkConstant.PIC_SAVE_DIR_NAME目录(不压缩)
     * <p>
     * Android10以下版本调用
     * <p>
     * Android10以上调用该方法{@link FileUtil#saveBitmapAboveQ(Context, Bitmap)}
     */
    public static Uri saveBitmapLegacy(Context context, Bitmap bitmap) {
        String picName = "IMG_" + System.currentTimeMillis();

        String pathFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
                + File.separator + AppFrameWorkConstant.PIC_SAVE_DIR_NAME;
        File file = new File(pathFolder);
        if (!file.exists()) {
            file.mkdirs();
        }
        try {
            file = new File(pathFolder, picName + ".png");
            if (!file.exists()) {
                file.createNewFile();
            }

            OutputStream os = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
            os.flush();
            os.close();

            String filePath = file.getAbsolutePath();
            Logger.i("FileUtil.saveBitmapLegacy file real path = " + filePath);
            MediaScannerConnection.scanFile(context, new String[]{filePath}, null, (path, uri) -> {
                if (uri != null) {
                    Logger.i("FileUtil.saveBitmapLegacy scanning operation succeeded and the file was added to the media database");
                } else {
                    Logger.i("FileUtil.saveBitmapLegacy scanning operation failed");
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(context, AppFrameWorkConstant.FILE_PROVIDER_AUTHORITY, file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

    /**
     * 保存bitmap到Pictures/AppFrameWorkConstant.PIC_SAVE_DIR_NAME目录(不压缩)
     * <p>
     * Android10以上版本调用
     * <p>
     * Android10以下调用该方法{@link FileUtil#saveBitmapLegacy(Context, Bitmap)}
     */
    public static Uri saveBitmapAboveQ(Context context, Bitmap bitmap) {
        String picName = "IMG_" + System.currentTimeMillis();
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DISPLAY_NAME, picName);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        values.put(MediaStore.Images.Media.TITLE, picName);
        values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + AppFrameWorkConstant.PIC_SAVE_DIR_NAME);
        values.put(MediaStore.Images.Media.IS_PENDING, 1);

        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        ContentResolver resolver = context.getContentResolver();
        Uri insertUri = resolver.insert(external, values);
        try {
            OutputStream os = null;
            if (insertUri != null) {
                os = resolver.openOutputStream(insertUri);
            }
            if (os != null) {
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);

                os.flush();
                os.close();
            }
            // Now that we're finished, release the "pending" status, and allow other apps to access it
            values.clear();
            values.put(MediaStore.Images.Media.IS_PENDING, 0);
            resolver.update(insertUri, values, null, null);

            //手动再扫描一次更新相册 部分手机相册无法响应由MediaStore.insert触发更新
            String filePath = Environment.getExternalStorageDirectory() + File.separator
                    + Environment.DIRECTORY_PICTURES + File.separator + AppFrameWorkConstant.PIC_SAVE_DIR_NAME
                    + File.separator + picName + ".png";
            Logger.i("FileUtil.saveBitmapAboveQ file real path = " + filePath);
            MediaScannerConnection.scanFile(context, new String[]{filePath}, null, (path, uri) -> {
                if (uri != null) {
                    Logger.i("FileUtil.saveBitmapAboveQ scanning operation succeeded and the file was added to the media database");
                } else {
                    Logger.i("FileUtil.saveBitmapAboveQ scanning operation failed");
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            if (insertUri != null) {
                resolver.delete(insertUri, null, null);
                insertUri = null;
            }
        }
        return insertUri;
    }

    public static Uri getUriByMediaStore(Context context, String fileName) {
        Uri queryUri = null;

        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        String[] projection = new String[]{MediaStore.Images.Media._ID};
        String selection = MediaStore.Images.Media.DISPLAY_NAME + "=?";
        String[] args = new String[]{fileName};

        Cursor cursor = context.getContentResolver().query(external, projection, selection, args, null);
        if (cursor != null) {
            int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
            if (cursor.moveToFirst()) {
                Long id = cursor.getLong(idColumn);
                queryUri = ContentUris.withAppendedId(external, id);
            }
            cursor.close();
        }
        return queryUri;
    }

    public static List<Uri> getUriListByMediaStore(Context context, String folderName) {
        List<Uri> list = new ArrayList<>();

        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        String[] projection = new String[]{MediaStore.Images.Media._ID};
        String selection = MediaStore.Images.Media.RELATIVE_PATH + " like ? ";
        String[] args = new String[]{"%" + folderName + "%"};

        Cursor cursor = context.getContentResolver().query(external, projection, selection, args, null);
        if (cursor != null) {
            int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
            while (cursor.moveToNext()) {
                Long id = cursor.getLong(idColumn);
                Uri queryUri = ContentUris.withAppendedId(external, id);
                list.add(queryUri);
            }
            cursor.close();
        }
        return list;
    }

    /**
     * 建议放到子线程调用该方法保存 避免UI线程卡顿
     * <p>
     * 保存bitmap到cache目录 内部流转的图片(不对外的图片) 不用MediaStore存储
     * 图片异常的时候会返回空图片地址
     *
     * @return 图片绝对路径
     */
    public static String saveBitmapToPrivateCache(Context context, Bitmap bitmap) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            /* options表示 如果不压缩是100，表示压缩率为0。如果是70，就表示压缩率是70，表示压缩30%; */
            int options = 100;
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
            // 循环判断如果压缩后图片是否大于2m并且压缩率>10继续压缩
            while (baos.toByteArray().length / 1024 > 2048 && options > 10) {
                baos.reset();
                options -= 10;
                // 这里压缩options%，把压缩后的数据存放到baos中
                bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
            }

            File file = createInternalCachePicFile(context);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
            return file.getAbsolutePath();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    //生成内部文件夹下临时子文件
    public static File createInternalCachePicFile(Context context) throws IOException {
        String dir = context.getExternalCacheDir() + File.separator + Environment.DIRECTORY_PICTURES + File.separator;
        File folder = new File(dir);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        return File.createTempFile(PNG_FILE_PREFIX, PNG_FILE_SUFFIX, folder);
    }

    //删除内部文件夹下生成的所有临时图片子文件
    public static void deleteInternalCachePicFiles(Context context) {
        String path = context.getExternalCacheDir() + File.separator + Environment.DIRECTORY_PICTURES + File.separator;
        File filePath = new File(path);
        if (!filePath.exists()) {
            return;
        }
        String name = "";
        for (File f : filePath.listFiles()) {
            if (f.isFile()) {
                name = f.getName();
                if (name.startsWith(PNG_FILE_PREFIX)) {
                    f.delete();
                }
            }
        }
    }

    //生成内部文件夹下临时子文件
    //storage/emulated/0/Android/data/com.xx.xx/files/Pictures
    public static File createInternalFilesDirPic(Context context) throws IOException {
        String dir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
        File folder = new File(dir);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        return File.createTempFile(PNG_FILE_PREFIX, PNG_FILE_SUFFIX, folder);
    }

    //删除内部文件夹下的某个子文件
    public static void deleteInternalFilesDirPic(Context context, String innerPath) {
        if (TextUtils.isEmpty(innerPath)) {
            return;
        }
        File file = new File(innerPath);
        if (file.exists()) {
            file.delete();
        }
    }

    public static boolean copyStream(InputStream input, OutputStream output) {
        try {
            int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 KB
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
            output.flush();
            output.close();
            input.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
